package DyingBaby.demo;

import DyingBaby.backend.common.AbstractCache;
import DyingBaby.backend.common.CacheConfig;
import DyingBaby.backend.common.CacheStrategy;

/**
 * LRU Cache Strategy Demonstration
 * Shows how to use LRU (Least Recently Used) cache strategy
 */
public class LRUCacheDemoEN {
    
    /**
     * Simple test cache implementation
     */
    static class TestCache extends AbstractCache<String> {
        public TestCache(int maxResource, CacheStrategy strategy) {
            super(maxResource, strategy);
        }
        
        @Override
        protected String getForCache(long key) throws Exception {
            // Simulate fetching data from data source
            System.out.println("Fetching data from source: " + key);
            return "Data_" + key;
        }
        
        @Override
        protected void releaseForCache(String obj) {
            // Simulate writing back to data source
            System.out.println("Writing back to source: " + obj);
        }
        
        public String getData(long key) throws Exception {
            return get(key);
        }
        
        public void releaseData(long key) {
            release(key);
        }
    }
    
    /**
     * Helper method to repeat a string n times (Java 8 compatible)
     */
    private static String repeatString(String str, int count) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) {
            sb.append(str);
        }
        return sb.toString();
    }
    
    public static void main(String[] args) {
        System.out.println("=== LRU Cache Strategy Demonstration ===\n");
        
        // Demonstrate Reference Count Strategy
        System.out.println("1. Reference Count Strategy Demo:");
        testReferenceCountStrategy();
        
        System.out.println("\n" + repeatString("=", 60) + "\n");
        
        // Demonstrate LRU Strategy
        System.out.println("2. LRU Strategy Demo:");
        testLRUStrategy();
        
        System.out.println("\n" + repeatString("=", 60) + "\n");
        
        // Demonstrate Configuration
        System.out.println("3. Cache Configuration Demo:");
        testCacheConfig();
    }
    
    /**
     * Test Reference Count Strategy
     */
    private static void testReferenceCountStrategy() {
        TestCache cache = new TestCache(3, CacheStrategy.REFERENCE_COUNT);
        
        try {
            System.out.println("Cache Strategy: " + cache.getStrategy().getDescription());
            
            // Add data
            System.out.println("\nAdding data:");
            cache.getData(1);
            cache.getData(2);
            cache.getData(3);
            
            System.out.println("Current stats: " + cache.getCacheStats());
            
            // Try to add 4th data (should throw exception)
            System.out.println("\nTrying to add 4th data:");
            try {
                cache.getData(4);
            } catch (Exception e) {
                System.out.println("Exception: " + e.getMessage());
            }
            
            // Release one data
            System.out.println("\nReleasing data 1:");
            cache.releaseData(1);
            System.out.println("Current stats: " + cache.getCacheStats());
            
            // Now can add new data
            System.out.println("\nAdding new data 4:");
            cache.getData(4);
            System.out.println("Current stats: " + cache.getCacheStats());
            
        } catch (Exception e) {
            System.out.println("Exception during test: " + e.getMessage());
        }
    }
    
    /**
     * Test LRU Strategy
     */
    private static void testLRUStrategy() {
        TestCache cache = new TestCache(3, CacheStrategy.LRU);
        
        try {
            System.out.println("Cache Strategy: " + cache.getStrategy().getDescription());
            
            // Add data
            System.out.println("\nAdding data:");
            cache.getData(1);
            cache.getData(2);
            cache.getData(3);
            
            System.out.println("Current stats: " + cache.getCacheStats());
            
            // Access data 1 to make it recently used
            System.out.println("\nAccessing data 1 (making it recently used):");
            cache.getData(1);
            System.out.println("Current stats: " + cache.getCacheStats());
            
            // Add 4th data (should evict least recently used data 2)
            System.out.println("\nAdding 4th data (should evict least recently used data 2):");
            cache.getData(4);
            System.out.println("Current stats: " + cache.getCacheStats());
            
            // Access data 2 again (should fetch from source)
            System.out.println("\nAccessing data 2 again:");
            cache.getData(2);
            System.out.println("Current stats: " + cache.getCacheStats());
            
        } catch (Exception e) {
            System.out.println("Exception during test: " + e.getMessage());
        }
    }
    
    /**
     * Test Cache Configuration
     */
    private static void testCacheConfig() {
        System.out.println("Current config: " + CacheConfig.getConfigInfo());
        
        // Test setting LRU strategy
        System.out.println("\nSetting cache strategy to LRU:");
        CacheConfig.setCacheStrategy(CacheStrategy.LRU);
        System.out.println("Updated config: " + CacheConfig.getConfigInfo());
        
        // Test setting Reference Count strategy
        System.out.println("\nSetting cache strategy to Reference Count:");
        CacheConfig.setCacheStrategy(CacheStrategy.REFERENCE_COUNT);
        System.out.println("Updated config: " + CacheConfig.getConfigInfo());
        
        // Reset to default config
        System.out.println("\nResetting to default config:");
        CacheConfig.resetToDefaults();
        System.out.println("Reset config: " + CacheConfig.getConfigInfo());
    }
}
